﻿using Mina.Core.Buffer;
using Mina.Core.Session;
using Mina.Transport.Socket;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using TinyUtil;

namespace HttpPerfLoad
{
    public partial class Form1 : Form
    {
        ConnectionManager connectionManager;
        RequestManager requestManager;
        AppSetting appsetting;
        public Form1()
        {
            InitializeComponent();
            this.Load += Form1_Load;
            this.FormClosing += Form1_FormClosing;
        }
        private bool closingForm;
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (!closingForm)
            {
                this.Stop();
                e.Cancel = !this.btnStart.Enabled;
                if (!e.Cancel)
                {

                    this.Hide();
                }
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            appsetting = JsonFile.Read<AppSetting>("appsetting.json", true);
            if (appsetting.numRequests != 0)
            {
                this.txtIp.Text = appsetting.ip;
                this.numPort.Value = appsetting.port;
                this.numConnections.Value = appsetting.numConnections;
                this.numRequests.Value = appsetting.numRequests;
                this.numRequestInterval.Value = appsetting.requestInterval;
                this.requestText.Text = appsetting.requestData;
            }
            t.Interval = 50;
            t.Tick += T_Tick;

        }

        System.Windows.Forms.Timer t = new System.Windows.Forms.Timer();
        private void btnStart_Click(object sender, EventArgs ee)
        {
            appsetting.ip = this.txtIp.Text;
            appsetting.port = (int)this.numPort.Value;
            appsetting.numConnections = (int)this.numConnections.Value;
            appsetting.numRequests = (int)this.numRequests.Value;
            appsetting.requestInterval = (int)this.numRequestInterval.Value;
            appsetting.requestData = this.requestText.Text;
            if (appsetting.numRequests > appsetting.numConnections)
            {
                MessageBox.Show("并发请求数量不能大于连接数量");
                return;
            }
            JsonFile.Write("appsetting.json", this.appsetting);
            this.btnStart.Enabled = false;
            this.btnStop.Enabled = true;
            if (connectionManager != null)
            {
                connectionManager.Stop();
                return;
            }
            this.progressBar1.Maximum = appsetting.numConnections;
            connectionManager = new ConnectionManager(this.txtIp.Text, (int)this.numPort.Value, (int)this.numConnections.Value);
            connectionManager.AllConnectionClosed += ConnectionManager_AllConnectionClosed;
            connectionManager.ConnectionProgress += ConnectionManager_ConnectionProgress;
            connectionManager.StatisticsTick += ConnectionManager_StatisticsTick;
            connectionManager.ConnectError += ConnectionManager_ConnectError;
            connectionManager.AllConnectionCompleted += ConnectionManager_AllConnectionCompleted;
            connectionManager.Start();
            t.Start();
        }

        private void ConnectionManager_AllConnectionClosed(object sender, EventArgs e)
        {
            this.Stop();
        }

        private void ConnectionManager_ConnectError(object sender, ConnectionError e)
        {
            if (e.ConnectionIndex == 0)
            {
                this.Stop();
            }
        }

        private TickInfo tickInfo;
        private void ConnectionManager_StatisticsTick(object sender, TickInfo e)
        {
            tickInfo = e;
            tickInfo.threads = (int)RequestManager.numThread;
        }

        public ProgressInfo progressInfo;
        private void ConnectionManager_ConnectionProgress(object sender, ProgressInfo e)
        {
            this.progressInfo = e;
        }

        private void T_Tick(object sender, EventArgs e)
        {
            if (progressInfo != null && requestManager == null)
            {
                this.progressBar1.Value = progressInfo.current;
            }

            if (this.tickInfo != null)
            {
                this.progressBar1.Value = tickInfo.aliveSessions;
                this.Text = $"HPL | C: {tickInfo.aliveSessions}, T: {tickInfo.threads}/{(appsetting.numRequests == 1 ? appsetting.numRequests : (int)Math.Ceiling(appsetting.numRequests / 2.0))}, W: {(tickInfo.avgWrite / 1024.0).ToString("f2")} KB/s, R: {(tickInfo.avgRead / 1024.0).ToString("f2")} KB/s, AVG_W: {(tickInfo.avgWrite / (double)RequestManager.numThread).ToString("f2")} bytes/s, AVGR: {(tickInfo.avgRead / (double)RequestManager.numThread).ToString("f2")} bytes/s";
            }
            if (this.connectionManager != null)
            {
                this.textBox1.Text = this.connectionManager.responseData;
                this.textBox2.Text = this.connectionManager.errorText;
            }
        }


        private void ConnectionManager_AllConnectionCompleted(object sender, EventArgs e)
        {
            if (connectionManager?.stopRequested ?? true)
                return;
            this.requestManager = new RequestManager(connectionManager.GetAliveSessions(), (int)this.numRequests.Value, this.requestText.Text, (int)this.numRequestInterval.Value);
            requestManager.AllThreadsRunToCompleted += RequestManager_AllThreadsRunToCompleted;
            requestManager.Start();
        }

        private void RequestManager_AllThreadsRunToCompleted(object sender, EventArgs e)
        {
            this.ResetManagers();
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            this.btnStop.Enabled = false; Stop();
        }

        private void Stop()
        {
            t.Stop();
            if (this.requestManager != null)
                this.requestManager.Stop();
            if (this.connectionManager != null)
            {
                this.connectionManager.Stop();
                new Thread(WaitThread).Start();
            }
        }
        private void ResetManagers()
        {
            this.connectionManager = null;
            this.requestManager = null;
            this.Invoke(new Action(() =>
            {
                this.progressBar1.Value = 0;
                this.btnStart.Enabled = true;
                this.btnStop.Enabled = false;
                this.Text = "HPL - Http Perf Load by tiny@sandsea.info 2018";
            }));
            if (this.closingForm)
            {
                this.Close();
            }
        }
        public void WaitThread(object state)
        {
            if (connectionManager == null)
                return;
            var connections = connectionManager.GetAliveSessions();
            while (!connections.All(x => x.SessionBroken) || RequestManager.numThread > 0)
            {
                Thread.Sleep(100);
            }
            ResetManagers();
        }
    }
}
